1 <?php
2
3 #########################################################
4 /*
5 ~~~~~~ LIST OF FUNCTIONS ~~~~~~
6 getTableList() -- returns an associative array (tableName => tableData, tableData is array(tableCaption, tableDescription, tableIcon)) of tables accessible by current user
7 get_table_groups() -- returns an associative array (table_group => tables_array)
8 getLoggedMemberID() -- returns memberID of logged member. If no login, returns anonymous memberID
9 getLoggedGroupID() -- returns groupID of logged member, or anonymous groupID
10 logOutMember() -- destroys session and logs member out.
11 logInMember() -- checks POST login. If not valid, redirects to index.php, else returns TRUE
12 getTablePermissions($tn) -- returns an array of permissions allowed for logged member to given table (allowAccess, allowInsert, allowView, allowEdit, allowDelete) -- allowAccess is set to true if any access level is allowed
13 get_sql_fields($tn) -- returns the SELECT part of the table view query
14 get_sql_from($tn[, true]) -- returns the FROM part of the table view query, with full joins, optionally skipping permissions if true passed as 2nd param.
15 get_joined_record($table, $id[, true]) -- returns assoc array of record values for given PK value of given table, with full joins, optionally skipping permissions if true passed as 3rd param.
16 get_defaults($table) -- returns assoc array of table fields as array keys and default values (or empty), excluding automatic values as array values
17 htmlUserBar() -- returns html code for displaying user login status to be used on top of pages.
18 showNotifications($msg, $class) -- returns html code for displaying a notification. If no parameters provided, processes the GET request for possible notifications.
19 parseMySQLDate(a, b) -- returns a if valid mysql date, or b if valid mysql date, or today if b is true, or empty if b is false.
20 parseCode(code) -- calculates and returns special values to be inserted in automatic fields.
21 addFilter(i, filterAnd, filterField, filterOperator, filterValue) -- enforce a filter over data
22 clearFilters() -- clear all filters
23 getMemberInfo() -- returns an array containing the currently signed-in member's info
24 loadView($view, $data) -- passes $data to templates/{$view}.php and returns the output
25 loadTable($table, $data) -- loads table template, passing $data to it
26 filterDropdownBy($filterable, $filterers, $parentFilterers, $parentPKField, $parentCaption, $parentTable, &$filterableCombo) -- applies cascading drop-downs for a lookup field, returns js code to be inserted into the page
27 br2nl($text) -- replaces all variations of HTML <br> tags with a new line character
28 htmlspecialchars_decode($text) -- inverse of htmlspecialchars()
29 entitiesToUTF8($text) -- convert unicode entities (e.g. Ӓ) to actual UTF8 characters, requires multibyte string PHP extension
30 func_get_args_byref() -- returns an array of arguments passed to a function, by reference
31 permissions_sql($table, $level) -- returns an array containing the FROM and WHERE additions for applying permissions to an SQL query
32 error_message($msg[, $back_url]) -- returns html code for a styled error message .. pass explicit false in second param to suppress back button
33 toMySQLDate($formattedDate, $sep = datalist_date_separator, $ord = datalist_date_format)
34 reIndex(&$arr) -- returns a copy of the given array, with keys replaced by 1-based numeric indices, and values replaced by original keys
35 get_embed($provider, $url[, $width, $height, $retrieve]) -- returns embed code for a given url (supported providers: youtube, googlemap)
36 check_record_permission($table, $id, $perm = 'view') -- returns true if current user has the specified permission $perm ('view', 'edit' or 'delete') for the given recors, false otherwise
37 NavMenus($options) -- returns the HTML code for the top navigation menus. $options is not implemented currently.
38 StyleSheet() -- returns the HTML code for included style sheet files to be placed in the <head> section.
39 getUploadDir($dir) -- if dir is empty, returns upload dir configured in defaultLang.php, else returns $dir.
40 PrepareUploadedFile($FieldName, $MaxSize, $FileTypes='jpg|jpeg|gif|png', $NoRename=false, $dir="") -- validates and moves uploaded file for given $FieldName into the given $dir (or the default one if empty)
41 get_home_links($homeLinks, $default_classes, $tgroup) -- process $homeLinks array and return custom links for homepage. Applies $default_classes to links if links have classes defined, and filters links by $tgroup (using '*' matches all table_group values)
42 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
43 */
44
45 #########################################################
46
47 function getTableList($skip_authentication = false){
48 $arrAccessTables = array();
49 $arrTables = array(
50 'patients' => array('Patients', '', 'resources/table_icons/administrator.png', 'None'),
51 'disease_symptoms' => array('Disease symptoms', '', 'resources/table_icons/health.png', 'None'),
52 'medical_records' => array('Medical Records', '', 'resources/table_icons/cash_terminal.png', 'None'),
53 'events' => array('Appointments', '', 'table.gif', 'None')
54 );
55 if($skip_authentication || getLoggedAdmin()) return $arrTables;
56
57 if(is_array($arrTables)){
58 foreach($arrTables as $tn => $tc){
59 $arrPerm = getTablePermissions($tn);
60 if($arrPerm[0]){
61 $arrAccessTables[$tn] = $tc;
62 }
63 }
64 }
65
66 return $arrAccessTables;
67 }
68
69 #########################################################
70
71 function get_table_groups($skip_authentication = false){
72 $tables = getTableList($skip_authentication);
73 $all_groups = array('None');
74
75 $groups = array();
76 foreach($all_groups as $grp){
77 foreach($tables as $tn => $td){
78 if($td[3] && $td[3] == $grp) $groups[$grp][] = $tn;
79 if(!$td[3]) $groups[0][] = $tn;
80 }
81 }
82
83 return $groups;
84 }
85
86 #########################################################
87
88 function getTablePermissions($tn){
89 static $table_permissions = array();
90 if(isset($table_permissions[$tn])) return $table_permissions[$tn];
91
92 $groupID = getLoggedGroupID();
93 $memberID = makeSafe(getLoggedMemberID());
94 $res_group = sql("select tableName, allowInsert, allowView, allowEdit, allowDelete from membership_grouppermissions where groupID='{$groupID}'", $eo);
95 $res_user = sql("select tableName, allowInsert, allowView, allowEdit, allowDelete from membership_userpermissions where lcase(memberID)='{$memberID}'", $eo);
96
97 while($row = db_fetch_assoc($res_group)){
98 $table_permissions[$row['tableName']] = array(
99 1 => intval($row['allowInsert']),
100 2 => intval($row['allowView']),
101 3 => intval($row['allowEdit']),
102 4 => intval($row['allowDelete']),
103 'insert' => intval($row['allowInsert']),
104 'view' => intval($row['allowView']),
105 'edit' => intval($row['allowEdit']),
106 'delete' => intval($row['allowDelete'])
107 );
108 }
109
110 // user-specific permissions, if specified, overwrite his group permissions
111 while($row = db_fetch_assoc($res_user)){
112 $table_permissions[$row['tableName']] = array(
113 1 => intval($row['allowInsert']),
114 2 => intval($row['allowView']),
115 3 => intval($row['allowEdit']),
116 4 => intval($row['allowDelete']),
117 'insert' => intval($row['allowInsert']),
118 'view' => intval($row['allowView']),
119 'edit' => intval($row['allowEdit']),
120 'delete' => intval($row['allowDelete'])
121 );
122 }
123
124 // if user has any type of access, set 'access' flag
125 foreach($table_permissions as $t => $p){
126 $table_permissions[$t]['access'] = $table_permissions[$t][0] = false;
127
128 if($p['insert'] || $p['view'] || $p['edit'] || $p['delete']){
129 $table_permissions[$t]['access'] = $table_permissions[$t][0] = true;
130 }
131 }
132
133 return $table_permissions[$tn];
134 }
135
136 #########################################################
137
138 function get_sql_fields($table_name){
139 $sql_fields = array(
140 'patients' => "`patients`.`id` as 'id', `patients`.`last_name` as 'last_name', `patients`.`first_name` as 'first_name', `patients`.`gender` as 'gender', `patients`.`sexual_orientation` as 'sexual_orientation', if(`patients`.`birth_date`,date_format(`patients`.`birth_date`,'%m/%d/%Y'),'') as 'birth_date', `patients`.`age` as 'age', `patients`.`image` as 'image', `patients`.`address` as 'address', `patients`.`city` as 'city', `patients`.`state` as 'state', `patients`.`zip` as 'zip', CONCAT_WS('-', LEFT(`patients`.`home_phone`,3), MID(`patients`.`home_phone`,4,3), RIGHT(`patients`.`home_phone`,4)) as 'home_phone', CONCAT_WS('-', LEFT(`patients`.`work_phone`,3), MID(`patients`.`work_phone`,4,3), RIGHT(`patients`.`work_phone`,4)) as 'work_phone', CONCAT_WS('-', LEFT(`patients`.`mobile`,3), MID(`patients`.`mobile`,4,3)) as 'mobile', `patients`.`tobacco_usage` as 'tobacco_usage', `patients`.`alcohol_intake` as 'alcohol_intake', `patients`.`history` as 'history', `patients`.`surgical_history` as 'surgical_history', `patients`.`obstetric_history` as 'obstetric_history', `patients`.`genetic_diseases` as 'genetic_diseases', `patients`.`contact_person` as 'contact_person', `patients`.`other_details` as 'other_details', `patients`.`comments` as 'comments', DATE_FORMAT(`patients`.`filed`, '%c/%e/%Y %l:%i%p') as 'filed', DATE_FORMAT(`patients`.`last_modified`, '%c/%e/%Y %l:%i%p') as 'last_modified'",
141 'disease_symptoms' => "`disease_symptoms`.`id` as 'id', `disease_symptoms`.`disease` as 'disease', `disease_symptoms`.`symptoms` as 'symptoms', `disease_symptoms`.`reference` as 'reference'",
142 'medical_records' => "`medical_records`.`id` as 'id', IF( CHAR_LENGTH(`patients1`.`last_name`) || CHAR_LENGTH(`patients1`.`first_name`), CONCAT_WS('', `patients1`.`last_name`, ',', `patients1`.`first_name`), '') as 'patient', `medical_records`.`image_1` as 'image_1', `medical_records`.`image_2` as 'image_2', `medical_records`.`image_3` as 'image_3', `medical_records`.`image_4` as 'image_4', `medical_records`.`image_5` as 'image_5', `medical_records`.`document_1` as 'document_1', `medical_records`.`document_2` as 'document_2', `medical_records`.`document_3` as 'document_3', `medical_records`.`document_4` as 'document_4', `medical_records`.`document_5` as 'document_5', `medical_records`.`description` as 'description'",
143 'events' => "`events`.`id` as 'id', `events`.`title` as 'title', if(`events`.`date`,date_format(`events`.`date`,'%m/%d/%Y'),'') as 'date', `events`.`status` as 'status', IF( CHAR_LENGTH(`patients1`.`last_name`) || CHAR_LENGTH(`patients1`.`first_name`), CONCAT_WS('', `patients1`.`last_name`, ',', `patients1`.`first_name`), '') as 'name_patient', TIME_FORMAT(`events`.`time`, '%r') as 'time', `events`.`prescription` as 'prescription', `events`.`diagnosis` as 'diagnosis', `events`.`comments` as 'comments'"
144 );
145
146 if(isset($sql_fields[$table_name])){
147 return $sql_fields[$table_name];
148 }
149
150 return false;
151 }
152
153 #########################################################
154
155 function get_sql_from($table_name, $skip_permissions = false){
156 $sql_from = array(
157 'patients' => "`patients` ",
158 'disease_symptoms' => "`disease_symptoms` ",
159 'medical_records' => "`medical_records` LEFT JOIN `patients` as patients1 ON `patients1`.`id`=`medical_records`.`patient` ",
160 'events' => "`events` LEFT JOIN `patients` as patients1 ON `patients1`.`id`=`events`.`name_patient` "
161 );
162
163 $pkey = array(
164 'patients' => 'id',
165 'disease_symptoms' => 'id',
166 'medical_records' => 'id',
167 'events' => 'id'
168 );
169
170 if(isset($sql_from[$table_name])){
171 if($skip_permissions) return $sql_from[$table_name];
172
173 // mm: build the query based on current member's permissions
174 $perm = getTablePermissions($table_name);
175 if($perm[2] == 1){ // view owner only
176 $sql_from[$table_name] .= ", membership_userrecords WHERE `{$table_name}`.`{$pkey[$table_name]}`=membership_userrecords.pkValue and membership_userrecords.tableName='{$table_name}' and lcase(membership_userrecords.memberID)='" . getLoggedMemberID() . "'";
177 }elseif($perm[2] == 2){ // view group only
178 $sql_from[$table_name] .= ", membership_userrecords WHERE `{$table_name}`.`{$pkey[$table_name]}`=membership_userrecords.pkValue and membership_userrecords.tableName='{$table_name}' and membership_userrecords.groupID='" . getLoggedGroupID() . "'";
179 }elseif($perm[2] == 3){ // view all
180 $sql_from[$table_name] .= ' WHERE 1=1';
181 }else{ // view none
182 return false;
183 }
184 return $sql_from[$table_name];
185 }
186
187 return false;
188 }
189
190 #########################################################
191
192 function get_joined_record($table, $id, $skip_permissions = false){
193 $sql_fields = get_sql_fields($table);
194 $sql_from = get_sql_from($table, $skip_permissions);
195
196 if(!$sql_fields || !$sql_from) return false;
197
198 $pk = getPKFieldName($table);
199 if(!$pk) return false;
200
201 $safe_id = makeSafe($id, false);
202 $sql = "SELECT {$sql_fields} FROM {$sql_from} AND `{$table}`.`{$pk}`='{$safe_id}'";
203 $eo['silentErrors'] = true;
204 $res = sql($sql, $eo);
205 if($row = db_fetch_assoc($res)) return $row;
206
207 return false;
208 }
209
210 #########################################################
211
212 function get_defaults($table){
213 /* array of tables and their fields, with default values (or empty), excluding automatic values */
214 $defaults = array(
215 'patients' => array(
216 'id' => '',
217 'last_name' => '',
218 'first_name' => '',
219 'gender' => 'Unknown',
220 'sexual_orientation' => 'Unknown',
221 'birth_date' => '',
222 'age' => '',
223 'image' => '',
224 'address' => '',
225 'city' => '',
226 'state' => '',
227 'zip' => '',
228 'home_phone' => '',
229 'work_phone' => '',
230 'mobile' => '',
231 'tobacco_usage' => 'Unknown',
232 'alcohol_intake' => 'Unknown',
233 'history' => 'Unknown',
234 'surgical_history' => '',
235 'obstetric_history' => '',
236 'genetic_diseases' => '',
237 'contact_person' => '',
238 'other_details' => '',
239 'comments' => '',
240 'filed' => '',
241 'last_modified' => ''
242 ),
243 'disease_symptoms' => array(
244 'id' => '',
245 'disease' => '',
246 'symptoms' => '',
247 'reference' => ''
248 ),
249 'medical_records' => array(
250 'id' => '',
251 'patient' => '',
252 'image_1' => '',
253 'image_2' => '',
254 'image_3' => '',
255 'image_4' => '',
256 'image_5' => '',
257 'document_1' => '',
258 'document_2' => '',
259 'document_3' => '',
260 'document_4' => '',
261 'document_5' => '',
262 'description' => ''
263 ),
264 'events' => array(
265 'id' => '',
266 'title' => '',
267 'date' => '',
268 'status' => '',
269 'name_patient' => '',
270 'time' => '12:00',
271 'prescription' => '',
272 'diagnosis' => '',
273 'comments' => ''
274 )
275 );
276
277 return isset($defaults[$table]) ? $defaults[$table] : array();
278 }
279
280 #########################################################
281
282 function getLoggedGroupID(){
283 if($_SESSION['memberGroupID']!=''){
284 return $_SESSION['memberGroupID'];
285 }else{
286 if(!setAnonymousAccess()) return false;
287 return getLoggedGroupID();
288 }
289 }
290
291 #########################################################
292
293 function getLoggedMemberID(){
294 if($_SESSION['memberID']!=''){
295 return strtolower($_SESSION['memberID']);
296 }else{
297 if(!setAnonymousAccess()) return false;
298 return getLoggedMemberID();
299 }
300 }
301
302 #########################################################
303
304 function setAnonymousAccess(){
305 $adminConfig = config('adminConfig');
306 $anon_group_safe = addslashes($adminConfig['anonymousGroup']);
307 $anon_user_safe = strtolower(addslashes($adminConfig['anonymousMember']));
308
309 $eo = array('silentErrors' => true);
310
311 $res = sql("select groupID from membership_groups where name='{$anon_group_safe}'", $eo);
312 if(!$res){ return false; }
313 $row = db_fetch_array($res); $anonGroupID = $row[0];
314
315 $_SESSION['memberGroupID'] = ($anonGroupID ? $anonGroupID : 0);
316
317 $res = sql("select lcase(memberID) from membership_users where lcase(memberID)='{$anon_user_safe}' and groupID='{$anonGroupID}'", $eo);
318 if(!$res){ return false; }
319 $row = db_fetch_array($res); $anonMemberID = $row[0];
320
321 $_SESSION['memberID'] = ($anonMemberID ? $anonMemberID : 0);
322
323 return true;
324 }
325
326 #########################################################
327
328 function logInMember(){
329 $redir = 'index.php';
330 if($_POST['signIn'] != ''){
331 if($_POST['username'] != '' && $_POST['password'] != ''){
332 $username = makeSafe(strtolower($_POST['username']));
333 $password = md5($_POST['password']);
334
335 if(sqlValue("select count(1) from membership_users where lcase(memberID)='$username' and passMD5='$password' and isApproved=1 and isBanned=0")==1){
336 $_SESSION['memberID']=$username;
337 $_SESSION['memberGroupID']=sqlValue("select groupID from membership_users where lcase(memberID)='$username'");
338 if($_POST['rememberMe']==1){
339 @setcookie('online_clinic_management_system_rememberMe', md5($username.$password), time()+86400*30);
340 }else{
341 @setcookie('online_clinic_management_system_rememberMe', '', time()-86400*30);
342 }
343
344 // hook: login_ok
345 if(function_exists('login_ok')){
346 $args=array();
347 if(!$redir=login_ok(getMemberInfo(), $args)){
348 $redir='index.php';
349 }
350 }
351
352 redirect($redir);
353 exit;
354 }
355 }
356
357 // hook: login_failed
358 if(function_exists('login_failed')){
359 $args=array();
360 login_failed(array(
361 'username' => $_POST['username'],
362 'password' => $_POST['password'],
363 'IP' => $_SERVER['REMOTE_ADDR']
364 ), $args);
365 }
366
367 if(!headers_sent()) header('HTTP/1.0 403 Forbidden');
368 redirect("index.php?loginFailed=1");
369 exit;
370 }elseif((!$_SESSION['memberID'] || $_SESSION['memberID']==$adminConfig['anonymousMember']) && $_COOKIE['online_clinic_management_system_rememberMe']!=''){
371 $chk=makeSafe($_COOKIE['online_clinic_management_system_rememberMe']);
372 if($username=sqlValue("select memberID from membership_users where convert(md5(concat(memberID, passMD5)), char)='$chk' and isBanned=0")){
373 $_SESSION['memberID']=$username;
374 $_SESSION['memberGroupID']=sqlValue("select groupID from membership_users where lcase(memberID)='$username'");
375 }
376 }
377 }
378
379 #########################################################
380
381 function logOutMember(){
382 logOutUser();
383 redirect("index.php?signIn=1");
384 }
385
386 #########################################################
387
388 function htmlUserBar(){
389 global $adminConfig, $Translation;
390 if(!defined('PREPEND_PATH')) define('PREPEND_PATH', '');
391
392 ob_start();
393 $home_page = (basename($_SERVER['PHP_SELF'])=='index.php' ? true : false);
394
395 ?>
396 <nav class="navbar navbar-default navbar-fixed-top hidden-print" role="navigation">
397 <div class="navbar-header">
398 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
399 <span class="sr-only">Toggle navigation</span>
400 <span class="icon-bar"></span>
401 <span class="icon-bar"></span>
402 <span class="icon-bar"></span>
403 </button>
404 <!-- application title is obtained from the name besides the yellow database icon in AppGini, use underscores for spaces -->
405 <a class="navbar-brand" href="<?php echo PREPEND_PATH; ?>index.php"><i class="glyphicon glyphicon-home"></i> online clinic management system</a>
406 </div>
407 <div class="collapse navbar-collapse">
408 <ul class="nav navbar-nav">
409 <?php if(!$home_page){ ?>
410 <?php echo NavMenus(); ?>
411 <?php } ?>
412 </ul>
413
414 <?php if(getLoggedAdmin()){ ?>
415 <ul class="nav navbar-nav">
416 <a href="<?php echo PREPEND_PATH; ?>admin/pageHome.php" class="btn btn-danger navbar-btn hidden-xs" title="<?php echo html_attr($Translation['admin area']); ?>"><i class="glyphicon glyphicon-cog"></i> <?php echo $Translation['admin area']; ?></a>
417 <a href="<?php echo PREPEND_PATH; ?>admin/pageHome.php" class="btn btn-danger navbar-btn visible-xs btn-lg" title="<?php echo html_attr($Translation['admin area']); ?>"><i class="glyphicon glyphicon-cog"></i> <?php echo $Translation['admin area']; ?></a>
418 </ul>
419 <?php } ?>
420
421 <?php if(!$_GET['signIn'] && !$_GET['loginFailed']){ ?>
422 <?php if(getLoggedMemberID() == $adminConfig['anonymousMember']){ ?>
423 <p class="navbar-text navbar-right"> </p>
424 <a href="<?php echo PREPEND_PATH; ?>index.php?signIn=1" class="btn btn-success navbar-btn navbar-right"><?php echo $Translation['sign in']; ?></a>
425 <p class="navbar-text navbar-right">
426 <?php echo $Translation['not signed in']; ?>
427 </p>
428 <?php }else{ ?>
429 <ul class="nav navbar-nav navbar-right hidden-xs" style="min-width: 330px;">
430 <a class="btn navbar-btn btn-default" href="<?php echo PREPEND_PATH; ?>index.php?signOut=1"><i class="glyphicon glyphicon-log-out"></i> <?php echo $Translation['sign out']; ?></a>
431 <p class="navbar-text">
432 <?php echo $Translation['signed as']; ?> <strong><a href="<?php echo PREPEND_PATH; ?>membership_profile.php" class="navbar-link"><?php echo getLoggedMemberID(); ?></a></strong>
433 </p>
434 </ul>
435 <ul class="nav navbar-nav visible-xs">
436 <a class="btn navbar-btn btn-default btn-lg visible-xs" href="<?php echo PREPEND_PATH; ?>index.php?signOut=1"><i class="glyphicon glyphicon-log-out"></i> <?php echo $Translation['sign out']; ?></a>
437 <p class="navbar-text text-center">
438 <?php echo $Translation['signed as']; ?> <strong><a href="<?php echo PREPEND_PATH; ?>membership_profile.php" class="navbar-link"><?php echo getLoggedMemberID(); ?></a></strong>
439 </p>
440 </ul>
441 <script>
442 /* periodically check if user is still signed in */
443 setInterval(function(){
444 $j.ajax({
445 url: '<?php echo PREPEND_PATH; ?>ajax_check_login.php',
446 success: function(username){
447 if(!username.length) window.location = '<?php echo PREPEND_PATH; ?>index.php?signIn=1';
448 }
449 });
450 }, 60000);
451 </script>
452 <?php } ?>
453 <?php } ?>
454 </div>
455 </nav>
456 <?php
457
458 $html = ob_get_contents();
459 ob_end_clean();
460
461 return $html;
462 }
463
464 #########################################################
465
466 function showNotifications($msg = '', $class = '', $fadeout = true){
467 global $Translation;
468
469 $notify_template_no_fadeout = '<div id="%%ID%%" class="alert alert-dismissable %%CLASS%%" style="display: none; padding-top: 6px; padding-bottom: 6px;">' .
470 '<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' .
471 '%%MSG%%</div>' .
472 '<script> jQuery(function(){ jQuery("#%%ID%%").show("slow"); }); </script>'."\n";
473 $notify_template = '<div id="%%ID%%" class="alert %%CLASS%%" style="display: none; padding-top: 6px; padding-bottom: 6px;">%%MSG%%</div>' .
474 '<script>' .
475 'jQuery(function(){' .
476 'jQuery("#%%ID%%").show("slow", function(){' .
477 'setTimeout(function(){ jQuery("#%%ID%%").hide("slow"); }, 4000);' .
478 '});' .
479 '});' .
480 '</script>'."\n";
481
482 if(!$msg){ // if no msg, use url to detect message to display
483 if($_REQUEST['record-added-ok'] != ''){
484 $msg = $Translation['new record saved'];
485 $class = 'alert-success';
486 }elseif($_REQUEST['record-added-error'] != ''){
487 $msg = $Translation['Couldn\'t save the new record'];
488 $class = 'alert-danger';
489 $fadeout = false;
490 }elseif($_REQUEST['record-updated-ok'] != ''){
491 $msg = $Translation['record updated'];
492 $class = 'alert-success';
493 }elseif($_REQUEST['record-updated-error'] != ''){
494 $msg = $Translation['Couldn\'t save changes to the record'];
495 $class = 'alert-danger';
496 $fadeout = false;
497 }elseif($_REQUEST['record-deleted-ok'] != ''){
498 $msg = $Translation['The record has been deleted successfully'];
499 $class = 'alert-success';
500 $fadeout = false;
501 }elseif($_REQUEST['record-deleted-error'] != ''){
502 $msg = $Translation['Couldn\'t delete this record'];
503 $class = 'alert-danger';
504 $fadeout = false;
505 }else{
506 return '';
507 }
508 }
509 $id = 'notification-' . rand();
510
511 $out = ($fadeout ? $notify_template : $notify_template_no_fadeout);
512 $out = str_replace('%%ID%%', $id, $out);
513 $out = str_replace('%%MSG%%', $msg, $out);
514 $out = str_replace('%%CLASS%%', $class, $out);
515
516 return $out;
517 }
518
519 #########################################################
520
521 function parseMySQLDate($date, $altDate){
522 // is $date valid?
523 if(preg_match("/^\d{4}-\d{1,2}-\d{1,2}$/", trim($date))){
524 return trim($date);
525 }
526
527 if($date != '--' && preg_match("/^\d{4}-\d{1,2}-\d{1,2}$/", trim($altDate))){
528 return trim($altDate);
529 }
530
531 if($date != '--' && $altDate && intval($altDate)==$altDate){
532 return @date('Y-m-d', @time() + ($altDate >= 1 ? $altDate - 1 : $altDate) * 86400);
533 }
534
535 return '';
536 }
537
538 #########################################################
539
540 function parseCode($code, $isInsert=true, $rawData=false){
541 if($isInsert){
542 $arrCodes=array(
543 '<%%creatorusername%%>' => $_SESSION['memberID'],
544 '<%%creatorgroupid%%>' => $_SESSION['memberGroupID'],
545 '<%%creatorip%%>' => $_SERVER['REMOTE_ADDR'],
546 '<%%creatorgroup%%>' => sqlValue("select name from membership_groups where groupID='{$_SESSION['memberGroupID']}'"),
547
548 '<%%creationdate%%>' => ($rawData ? @date('Y-m-d') : @date('n/j/Y')),
549 '<%%creationtime%%>' => ($rawData ? @date('H:i:s') : @date('h:i:s a')),
550 '<%%creationdatetime%%>' => ($rawData ? @date('Y-m-d H:i:s') : @date('n/j/Y h:i:s a')),
551 '<%%creationtimestamp%%>' => ($rawData ? @date('Y-m-d H:i:s') : @time())
552 );
553 }else{
554 $arrCodes=array(
555 '<%%editorusername%%>' => $_SESSION['memberID'],
556 '<%%editorgroupid%%>' => $_SESSION['memberGroupID'],
557 '<%%editorip%%>' => $_SERVER['REMOTE_ADDR'],
558 '<%%editorgroup%%>' => sqlValue("select name from membership_groups where groupID='{$_SESSION['memberGroupID']}'"),
559
560 '<%%editingdate%%>' => ($rawData ? @date('Y-m-d') : @date('n/j/Y')),
561 '<%%editingtime%%>' => ($rawData ? @date('H:i:s') : @date('h:i:s a')),
562 '<%%editingdatetime%%>' => ($rawData ? @date('Y-m-d H:i:s') : @date('n/j/Y h:i:s a')),
563 '<%%editingtimestamp%%>' => ($rawData ? @date('Y-m-d H:i:s') : @time())
564 );
565 }
566
567 $pc=str_ireplace(array_keys($arrCodes), array_values($arrCodes), $code);
568
569 return $pc;
570 }
571
572 #########################################################
573
574 function addFilter($index, $filterAnd, $filterField, $filterOperator, $filterValue){
575 // validate input
576 if($index < 1 || $index > 80 || !is_int($index)) return false;
577 if($filterAnd != 'or') $filterAnd = 'and';
578 $filterField = intval($filterField);
579
580 /* backward compatibility */
581 if(in_array($filterOperator, $GLOBALS['filter_operators'])){
582 $filterOperator = array_search($filterOperator, $GLOBALS['filter_operators']);
583 }
584
585 if(!in_array($filterOperator, array_keys($GLOBALS['filter_operators']))){
586 $filterOperator = 'like';
587 }
588
589 if(!$filterField){
590 $filterOperator = '';
591 $filterValue = '';
592 }
593
594 $_REQUEST['FilterAnd'][$index] = $filterAnd;
595 $_REQUEST['FilterField'][$index] = $filterField;
596 $_REQUEST['FilterOperator'][$index] = $filterOperator;
597 $_REQUEST['FilterValue'][$index] = $filterValue;
598
599 return true;
600 }
601
602 #########################################################
603
604 function clearFilters(){
605 for($i=1; $i<=80; $i++){
606 addFilter($i, '', 0, '', '');
607 }
608 }
609
610 #########################################################
611
612 function getMemberInfo($memberID = ''){
613 static $member_info = array();
614
615 if(!$memberID){
616 $memberID = getLoggedMemberID();
617 }
618
619 // return cached results, if present
620 if(isset($member_info[$memberID])) return $member_info[$memberID];
621
622 $adminConfig = config('adminConfig');
623 $mi = array();
624
625 if($memberID){
626 $res = sql("select * from membership_users where memberID='" . makeSafe($memberID) . "'", $eo);
627 if($row = db_fetch_assoc($res)){
628 $mi = array(
629 'username' => $memberID,
630 'groupID' => $row['groupID'],
631 'group' => sqlValue("select name from membership_groups where groupID='{$row['groupID']}'"),
632 'admin' => ($adminConfig['adminUsername'] == $memberID ? true : false),
633 'email' => $row['email'],
634 'custom' => array(
635 $row['custom1'],
636 $row['custom2'],
637 $row['custom3'],
638 $row['custom4']
639 ),
640 'banned' => ($row['isBanned'] ? true : false),
641 'approved' => ($row['isApproved'] ? true : false),
642 'signupDate' => @date('n/j/Y', @strtotime($row['signupDate'])),
643 'comments' => $row['comments'],
644 'IP' => $_SERVER['REMOTE_ADDR']
645 );
646
647 // cache results
648 $member_info[$memberID] = $mi;
649 }
650 }
651
652 return $mi;
653 }
654
655 #########################################################
656
657 if(!function_exists('str_ireplace')){
658 function str_ireplace($search, $replace, $subject){
659 $ret=$subject;
660 if(is_array($search)){
661 for($i=0; $i<count($search); $i++){
662 $ret=str_ireplace($search[$i], $replace[$i], $ret);
663 }
664 }else{
665 $ret=preg_replace('/'.preg_quote($search, '/').'/i', $replace, $ret);
666 }
667
668 return $ret;
669 }
670 }
671
672 #########################################################
673
674 /**
675 * Loads a given view from the templates folder, passing the given data to it
676 * @param $view the name of a php file (without extension) to be loaded from the 'templates' folder
677 * @param $the_data_to_pass_to_the_view (optional) associative array containing the data to pass to the view
678 * @return the output of the parsed view as a string
679 */
680 function loadView($view, $the_data_to_pass_to_the_view=false){
681 global $Translation;
682
683 $view = dirname(__FILE__)."/templates/$view.php";
684 if(!is_file($view)) return false;
685
686 if(is_array($the_data_to_pass_to_the_view)){
687 foreach($the_data_to_pass_to_the_view as $k => $v)
688 $$k = $v;
689 }
690 unset($the_data_to_pass_to_the_view, $k, $v);
691
692 ob_start();
693 @include($view);
694 $out=ob_get_contents();
695 ob_end_clean();
696
697 return $out;
698 }
699
700 #########################################################
701
702 /**
703 * Loads a table template from the templates folder, passing the given data to it
704 * @param $table_name the name of the table whose template is to be loaded from the 'templates' folder
705 * @param $the_data_to_pass_to_the_table associative array containing the data to pass to the table template
706 * @return the output of the parsed table template as a string
707 */
708 function loadTable($table_name, $the_data_to_pass_to_the_table = array()){
709 $dont_load_header = $the_data_to_pass_to_the_table['dont_load_header'];
710 $dont_load_footer = $the_data_to_pass_to_the_table['dont_load_footer'];
711
712 $header = $table = $footer = '';
713
714 if(!$dont_load_header){
715 // try to load tablename-header
716 if(!($header = loadView("{$table_name}-header", $the_data_to_pass_to_the_table))){
717 $header = loadView('table-common-header', $the_data_to_pass_to_the_table);
718 }
719 }
720
721 $table = loadView($table_name, $the_data_to_pass_to_the_table);
722
723 if(!$dont_load_footer){
724 // try to load tablename-footer
725 if(!($footer = loadView("{$table_name}-footer", $the_data_to_pass_to_the_table))){
726 $footer = loadView('table-common-footer', $the_data_to_pass_to_the_table);
727 }
728 }
729
730 return "{$header}{$table}{$footer}";
731 }
732
733 #########################################################
734
735 function filterDropdownBy($filterable, $filterers, $parentFilterers, $parentPKField, $parentCaption, $parentTable, &$filterableCombo){
736 $filterersArray = explode(',', $filterers);
737 $parentFilterersArray = explode(',', $parentFilterers);
738 $parentFiltererList = '`' . implode('`, `', $parentFilterersArray) . '`';
739 $res=sql("SELECT `$parentPKField`, $parentCaption, $parentFiltererList FROM `$parentTable` ORDER BY 2", $eo);
740 $filterableData = array();
741 while($row=db_fetch_row($res)){
742 $filterableData[$row[0]] = $row[1];
743 $filtererIndex = 0;
744 foreach($filterersArray as $filterer){
745 $filterableDataByFilterer[$filterer][$row[$filtererIndex + 2]][$row[0]] = $row[1];
746 $filtererIndex++;
747 }
748 $row[0] = addslashes($row[0]);
749 $row[1] = addslashes($row[1]);
750 $jsonFilterableData .= "\"{$row[0]}\":\"{$row[1]}\",";
751 }
752 $jsonFilterableData .= '}';
753 $jsonFilterableData = '{'.str_replace(',}', '}', $jsonFilterableData);
754 $filterJS = "\nvar {$filterable}_data = $jsonFilterableData;";
755
756 foreach($filterersArray as $filterer){
757 if(is_array($filterableDataByFilterer[$filterer])) foreach($filterableDataByFilterer[$filterer] as $filtererItem => $filterableItem){
758 $jsonFilterableDataByFilterer[$filterer] .= '"'.addslashes($filtererItem).'":{';
759 foreach($filterableItem as $filterableItemID => $filterableItemData){
760 $jsonFilterableDataByFilterer[$filterer] .= '"'.addslashes($filterableItemID).'":"'.addslashes($filterableItemData).'",';
761 }
762 $jsonFilterableDataByFilterer[$filterer] .= '},';
763 }
764 $jsonFilterableDataByFilterer[$filterer] .= '}';
765 $jsonFilterableDataByFilterer[$filterer] = '{'.str_replace(',}', '}', $jsonFilterableDataByFilterer[$filterer]);
766
767 $filterJS.="\n\n// code for filtering {$filterable} by {$filterer}\n";
768 $filterJS.="\nvar {$filterable}_data_by_{$filterer} = {$jsonFilterableDataByFilterer[$filterer]}; ";
769 $filterJS.="\nvar selected_{$filterable} = \$j('#{$filterable}').val();";
770 $filterJS.="\nvar {$filterable}_change_by_{$filterer} = function(){";
771 $filterJS.="\n\t$('{$filterable}').options.length=0;";
772 $filterJS.="\n\t$('{$filterable}').options[0] = new Option();";
773 $filterJS.="\n\tif(\$j('#{$filterer}').val()){";
774 $filterJS.="\n\t\tfor({$filterable}_item in {$filterable}_data_by_{$filterer}[\$j('#{$filterer}').val()]){";
775 $filterJS.="\n\t\t\t$('{$filterable}').options[$('{$filterable}').options.length] = new Option(";
776 $filterJS.="\n\t\t\t\t{$filterable}_data_by_{$filterer}[\$j('#{$filterer}').val()][{$filterable}_item],";
777 $filterJS.="\n\t\t\t\t{$filterable}_item,";
778 $filterJS.="\n\t\t\t\t({$filterable}_item == selected_{$filterable} ? true : false),";
779 $filterJS.="\n\t\t\t\t({$filterable}_item == selected_{$filterable} ? true : false)";
780 $filterJS.="\n\t\t\t);";
781 $filterJS.="\n\t\t}";
782 $filterJS.="\n\t}else{";
783 $filterJS.="\n\t\tfor({$filterable}_item in {$filterable}_data){";
784 $filterJS.="\n\t\t\t$('{$filterable}').options[$('{$filterable}').options.length] = new Option(";
785 $filterJS.="\n\t\t\t\t{$filterable}_data[{$filterable}_item],";
786 $filterJS.="\n\t\t\t\t{$filterable}_item,";
787 $filterJS.="\n\t\t\t\t({$filterable}_item == selected_{$filterable} ? true : false),";
788 $filterJS.="\n\t\t\t\t({$filterable}_item == selected_{$filterable} ? true : false)";
789 $filterJS.="\n\t\t\t);";
790 $filterJS.="\n\t\t}";
791 $filterJS.="\n\t\tif(selected_{$filterable} && selected_{$filterable} == \$j('#{$filterable}').val()){";
792 $filterJS.="\n\t\t\tfor({$filterer}_item in {$filterable}_data_by_{$filterer}){";
793 $filterJS.="\n\t\t\t\tfor({$filterable}_item in {$filterable}_data_by_{$filterer}[{$filterer}_item]){";
794 $filterJS.="\n\t\t\t\t\tif({$filterable}_item == selected_{$filterable}){";
795 $filterJS.="\n\t\t\t\t\t\t$('{$filterer}').value = {$filterer}_item;";
796 $filterJS.="\n\t\t\t\t\t\tbreak;";
797 $filterJS.="\n\t\t\t\t\t}";
798 $filterJS.="\n\t\t\t\t}";
799 $filterJS.="\n\t\t\t\tif({$filterable}_item == selected_{$filterable}) break;";
800 $filterJS.="\n\t\t\t}";
801 $filterJS.="\n\t\t}";
802 $filterJS.="\n\t}";
803 $filterJS.="\n\t$('{$filterable}').highlight();";
804 $filterJS.="\n};";
805 $filterJS.="\n$('{$filterer}').observe('change', function(){ window.setTimeout({$filterable}_change_by_{$filterer}, 25); });";
806 $filterJS.="\n";
807 }
808
809 $filterableCombo = new Combo;
810 $filterableCombo->ListType = 0;
811 $filterableCombo->ListItem = array_slice(array_values($filterableData), 0, 10);
812 $filterableCombo->ListData = array_slice(array_keys($filterableData), 0, 10);
813 $filterableCombo->SelectName = $filterable;
814 $filterableCombo->AllowNull = true;
815
816 return $filterJS;
817 }
818
819 #########################################################
820 function br2nl($text){
821 return preg_replace('/\<br(\s*)?\/?\>/i', "\n", $text);
822 }
823
824 #########################################################
825
826 if(!function_exists('htmlspecialchars_decode')){
827 function htmlspecialchars_decode($string, $quote_style = ENT_COMPAT){
828 return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style)));
829 }
830 }
831
832 #########################################################
833
834 function entitiesToUTF8($input){
835 return preg_replace_callback('/(&#[0-9]+;)/', '_toUTF8', $input);
836 }
837
838 function _toUTF8($m){
839 if(function_exists('mb_convert_encoding')){
840 return mb_convert_encoding($m[1], "UTF-8", "HTML-ENTITIES");
841 }else{
842 return $m[1];
843 }
844 }
845
846 #########################################################
847
848 function func_get_args_byref() {
849 if(!function_exists('debug_backtrace')) return false;
850
851 $trace = debug_backtrace();
852 return $trace[1]['args'];
853 }
854
855 #########################################################
856
857 function permissions_sql($table, $level = 'all'){
858 if(!in_array($level, array('user', 'group'))){ $level = 'all'; }
859 $perm = getTablePermissions($table);
860 $from = '';
861 $where = '';
862 $pk = getPKFieldName($table);
863
864 if($perm[2] == 1 || ($perm[2] > 1 && $level == 'user')){ // view owner only
865 $from = 'membership_userrecords';
866 $where = "(`$table`.`$pk`=membership_userrecords.pkValue and membership_userrecords.tableName='$table' and lcase(membership_userrecords.memberID)='".getLoggedMemberID()."')";
867 }elseif($perm[2] == 2 || ($perm[2] > 2 && $level == 'group')){ // view group only
868 $from = 'membership_userrecords';
869 $where = "(`$table`.`$pk`=membership_userrecords.pkValue and membership_userrecords.tableName='$table' and membership_userrecords.groupID='".getLoggedGroupID()."')";
870 }elseif($perm[2] == 3){ // view all
871 // no further action
872 }elseif($perm[2] == 0){ // view none
873 return false;
874 }
875
876 return array('where' => $where, 'from' => $from, 0 => $where, 1 => $from);
877 }
878
879 #########################################################
880
881 function error_message($msg, $back_url = '', $full_page = true){
882 $curr_dir = dirname(__FILE__);
883 global $Translation;
884
885 ob_start();
886
887 if($full_page) include_once($curr_dir . '/header.php');
888
889 echo '<div class="panel panel-danger">';
890 echo '<div class="panel-heading"><h3 class="panel-title">' . $Translation['error:'] . '</h3></div>';
891 echo '<div class="panel-body"><p class="text-danger">' . $msg . '</p>';
892 if($back_url !== false){ // explicitly passing false suppresses the back link completely
893 echo '<div class="text-center">';
894 if($back_url){
895 echo '<a href="' . $back_url . '" class="btn btn-danger btn-lg vspacer-lg"><i class="glyphicon glyphicon-chevron-left"></i> ' . $Translation['< back'] . '</a>';
896 }else{
897 echo '<a href="#" class="btn btn-danger btn-lg vspacer-lg" onclick="history.go(-1); return false;"><i class="glyphicon glyphicon-chevron-left"></i> ' . $Translation['< back'] . '</a>';
898 }
899 echo '</div>';
900 }
901 echo '</div>';
902 echo '</div>';
903
904 if($full_page) include_once($curr_dir . '/footer.php');
905
906 $out = ob_get_contents();
907 ob_end_clean();
908
909 return $out;
910 }
911
912 #########################################################
913
914 function toMySQLDate($formattedDate, $sep = datalist_date_separator, $ord = datalist_date_format){
915 // extract date elements
916 $de=explode($sep, $formattedDate);
917 $mySQLDate=intval($de[strpos($ord, 'Y')]).'-'.intval($de[strpos($ord, 'm')]).'-'.intval($de[strpos($ord, 'd')]);
918 return $mySQLDate;
919 }
920
921 #########################################################
922
923 function reIndex(&$arr){
924 $i=1;
925 foreach($arr as $n=>$v){
926 $arr2[$i]=$n;
927 $i++;
928 }
929 return $arr2;
930 }
931
932 #########################################################
933
934 function get_embed($provider, $url, $max_width = '', $max_height = '', $retrieve = 'html'){
935 global $Translation;
936 if(!$url) return '';
937
938 $providers = array(
939 'youtube' => array('oembed' => 'http://www.youtube.com/oembed?'),
940 'googlemap' => array('oembed' => '', 'regex' => '/^http.*\.google\..*maps/i')
941 );
942
943 if(!isset($providers[$provider])){
944 return '<div class="text-danger">' . $Translation['invalid provider'] . '</div>';
945 }
946
947 if(isset($providers[$provider]['regex']) && !preg_match($providers[$provider]['regex'], $url)){
948 return '<div class="text-danger">' . $Translation['invalid url'] . '</div>';
949 }
950
951 if($providers[$provider]['oembed']){
952 $oembed = $providers[$provider]['oembed'] . 'url=' . urlencode($url) . "&maxwidth={$max_width}&maxheight={$max_height}&format=json";
953 $data_json = request_cache($oembed);
954
955 $data = json_decode($data_json, true);
956 if($data === null){
957 /* an error was returned rather than a json string */
958 if($retrieve == 'html') return "<div class=\"text-danger\">{$data_json}\n<!-- {$oembed} --></div>";
959 return '';
960 }
961
962 return (isset($data[$retrieve]) ? $data[$retrieve] : $data['html']);
963 }
964
965 /* special cases (where there is no oEmbed provider) */
966 if($provider == 'googlemap') return get_embed_googlemap($url, $max_width, $max_height, $retrieve);
967
968 return '<div class="text-danger">Invalid provider!</div>';
969 }
970
971 #########################################################
972
973 function get_embed_googlemap($url, $max_width = '', $max_height = '', $retrieve = 'html'){
974 global $Translation;
975 $url_parts = parse_url($url);
976 $coords_regex = '/-?\d+(\.\d+)?[,+]-?\d+(\.\d+)?(,\d{1,2}z)?/'; /* https://stackoverflow.com/questions/2660201 */
977
978 if(preg_match($coords_regex, $url_parts['path'] . '?' . $url_parts['query'], $m)){
979 list($lat, $long, $zoom) = explode(',', $m[0]);
980 $zoom = intval($zoom);
981 if(!$zoom) $zoom = 10; /* default zoom */
982 if(!$max_height) $max_height = 360;
983 if(!$max_width) $max_width = 480;
984
985 $api_key = '';
986 $embed_url = "https://www.google.com/maps/embed/v1/view?key={$api_key}¢er={$lat},{$long}&zoom={$zoom}&maptype=roadmap";
987 $thumbnail_url = "https://maps.googleapis.com/maps/api/staticmap?key={$api_key}¢er={$lat},{$long}&zoom={$zoom}&maptype=roadmap&size={$max_width}x{$max_height}";
988
989 if($retrieve == 'html'){
990 return "<iframe width=\"{$max_width}\" height=\"{$max_height}\" frameborder=\"0\" style=\"border:0\" src=\"{$embed_url}\"></iframe>";
991 }else{
992 return $thumbnail_url;
993 }
994 }else{
995 return '<div class="text-danger">' . $Translation['cant retrieve coordinates from url'] . '</div>';
996 }
997 }
998
999 #########################################################
1000
1001 function request_cache($request, $force_fetch = false){
1002 $max_cache_lifetime = 7 * 86400; /* max cache lifetime in seconds before refreshing from source */
1003
1004 /* membership_cache table exists? if not, create it */
1005 static $cache_table_exists = false;
1006 if(!$cache_table_exists && !$force_fetch){
1007 $te = sqlValue("show tables like 'membership_cache'");
1008 if(!$te){
1009 if(!sql("CREATE TABLE `membership_cache` (`request` VARCHAR(100) NOT NULL, `request_ts` INT, `response` TEXT NOT NULL, PRIMARY KEY (`request`))", $eo)){
1010 /* table can't be created, so force fetching request */
1011 return request_cache($request, true);
1012 }
1013 }
1014 $cache_table_exists = true;
1015 }
1016
1017 /* retrieve response from cache if exists */
1018 if(!$force_fetch){
1019 $res = sql("select response, request_ts from membership_cache where request='" . md5($request) . "'", $eo);
1020 if(!$row = db_fetch_array($res)) return request_cache($request, true);
1021
1022 $response = $row[0];
1023 $response_ts = $row[1];
1024 if($response_ts < time() - $max_cache_lifetime) return request_cache($request, true);
1025 }
1026
1027 /* if no response in cache, issue a request */
1028 if(!$response || $force_fetch){
1029 $response = @file_get_contents($request);
1030 if($response === false){
1031 $error = error_get_last();
1032 $error_message = preg_replace('/.*: (.*)/', '$1', $error['message']);
1033 return $error_message;
1034 }elseif($cache_table_exists){
1035 /* store response in cache */
1036 $ts = time();
1037 sql("replace into membership_cache set request='" . md5($request) . "', request_ts='{$ts}', response='" . makeSafe($response, false) . "'", $eo);
1038 }
1039 }
1040
1041 return $response;
1042 }
1043
1044 #########################################################
1045
1046 function check_record_permission($table, $id, $perm = 'view'){
1047 if($perm != 'edit' && $perm != 'delete') $perm = 'view';
1048
1049 $perms = getTablePermissions($table);
1050 if(!$perms[$perm]) return false;
1051
1052 $safe_id = makeSafe($id);
1053 $safe_table = makeSafe($table);
1054
1055 if($perms[$perm] == 1){ // own records only
1056 $username = getLoggedMemberID();
1057 $owner = sqlValue("select memberID from membership_userrecords where tableName='{$safe_table}' and pkValue='{$safe_id}'");
1058 if($owner == $username) return true;
1059 }elseif($perms[$perm] == 2){ // group records
1060 $group_id = getLoggedGroupID();
1061 $owner_group_id = sqlValue("select groupID from membership_userrecords where tableName='{$safe_table}' and pkValue='{$safe_id}'");
1062 if($owner_group_id == $group_id) return true;
1063 }elseif($perms[$perm] == 3){ // all records
1064 return true;
1065 }
1066
1067 return false;
1068 }
1069
1070 #########################################################
1071
1072 function NavMenus($options = array()){
1073 if(!defined('PREPEND_PATH')) define('PREPEND_PATH', '');
1074 global $Translation;
1075 $prepend_path = PREPEND_PATH;
1076
1077 /* default options */
1078 if(empty($options)){
1079 $options = array(
1080 'tabs' => 7
1081 );
1082 }
1083
1084 $table_group_name = array_keys(get_table_groups()); /* 0 => group1, 1 => group2 .. */
1085 /* if only one group named 'None', set to translation of 'select a table' */
1086 if((count($table_group_name) == 1 && $table_group_name[0] == 'None') || count($table_group_name) < 1) $table_group_name[0] = $Translation['select a table'];
1087 $table_group_index = array_flip($table_group_name); /* group1 => 0, group2 => 1 .. */
1088 $menu = array_fill(0, count($table_group_name), '');
1089
1090 $t = time();
1091 $arrTables = getTableList();
1092 if(is_array($arrTables)){
1093 foreach($arrTables as $tn => $tc){
1094 /* ---- list of tables where hide link in nav menu is set ---- */
1095 $tChkHL = array_search($tn, array('medical_records'));
1096
1097 /* ---- list of tables where filter first is set ---- */
1098 $tChkFF = array_search($tn, array());
1099 if($tChkFF !== false && $tChkFF !== null){
1100 $searchFirst = '&Filter_x=1';
1101 }else{
1102 $searchFirst = '';
1103 }
1104
1105 /* when no groups defined, $table_group_index['None'] is NULL, so $menu_index is still set to 0 */
1106 $menu_index = intval($table_group_index[$tc[3]]);
1107 if(!$tChkHL && $tChkHL !== 0) $menu[$menu_index] .= "<li><a href=\"{$prepend_path}{$tn}_view.php?t={$t}{$searchFirst}\"><img src=\"{$prepend_path}" . ($tc[2] ? $tc[2] : 'blank.gif') . "\" height=\"32\"> {$tc[0]}</a></li>";
1108 }
1109 }
1110
1111 // custom nav links, as defined in "hooks/links-navmenu.php"
1112 global $navLinks;
1113 if(is_array($navLinks)){
1114 $memberInfo = getMemberInfo();
1115 $links_added = array();
1116 foreach($navLinks as $link){
1117 if(!isset($link['url']) || !isset($link['title'])) continue;
1118 if($memberInfo['admin'] || @in_array($memberInfo['group'], $link['groups']) || @in_array('*', $link['groups'])){
1119 $menu_index = intval($link['table_group']);
1120 if(!$links_added[$menu_index]) $menu[$menu_index] .= '<li class="divider"></li>';
1121
1122 /* add prepend_path to custom links if they aren't absolute links */
1123 if(!preg_match('/^(http|\/\/)/i', $link['url'])) $link['url'] = $prepend_path . $link['url'];
1124 if(!preg_match('/^(http|\/\/)/i', $link['icon']) && $link['icon']) $link['icon'] = $prepend_path . $link['icon'];
1125
1126 $menu[$menu_index] .= "<li><a href=\"{$link['url']}\"><img src=\"" . ($link['icon'] ? $link['icon'] : "{$prepend_path}blank.gif") . "\" height=\"32\"> {$link['title']}</a></li>";
1127 $links_added[$menu_index]++;
1128 }
1129 }
1130 }
1131
1132 $menu_wrapper = '';
1133 for($i = 0; $i < count($menu); $i++){
1134 $menu_wrapper .= <<<EOT
1135 <li class="dropdown">
1136 <a href="#" class="dropdown-toggle" data-toggle="dropdown">{$table_group_name[$i]} <b class="caret"></b></a>
1137 <ul class="dropdown-menu" role="menu">{$menu[$i]}</ul>
1138 </li>
1139 EOT;
1140 }
1141
1142 return $menu_wrapper;
1143 }
1144
1145 #########################################################
1146
1147 function StyleSheet(){
1148 if(!defined('PREPEND_PATH')) define('PREPEND_PATH', '');
1149 $prepend_path = PREPEND_PATH;
1150
1151 $css_links = <<<EOT
1152
1153 <link rel="stylesheet" href="{$prepend_path}resources/initializr/css/bootstrap.css">
1154 <!--[if gt IE 8]><!-->
1155 <link rel="stylesheet" href="{$prepend_path}resources/initializr/css/bootstrap-theme.css">
1156 <!--<![endif]-->';
1157 <link rel="stylesheet" href="{$prepend_path}resources/lightbox/css/lightbox.css" media="screen">
1158 <link rel="stylesheet" href="{$prepend_path}resources/select2/select2.css" media="screen">
1159 <link rel="stylesheet" href="{$prepend_path}resources/timepicker/bootstrap-timepicker.min.css" media="screen">
1160 <link rel="stylesheet" href="{$prepend_path}dynamic.css.php">
1161 EOT;
1162
1163 return $css_links;
1164 }
1165
1166 #########################################################
1167
1168 function getUploadDir($dir){
1169 global $Translation;
1170
1171 if($dir==""){
1172 $dir=$Translation['ImageFolder'];
1173 }
1174
1175 if(substr($dir, -1)!="/"){
1176 $dir.="/";
1177 }
1178
1179 return $dir;
1180 }
1181
1182 #########################################################
1183
1184 function PrepareUploadedFile($FieldName, $MaxSize, $FileTypes='jpg|jpeg|gif|png', $NoRename=false, $dir=""){
1185 global $Translation;
1186 $f = $_FILES[$FieldName];
1187
1188 $dir = getUploadDir($dir);
1189
1190 /* get php.ini upload_max_filesize in bytes */
1191 $php_upload_size_limit = trim(ini_get('upload_max_filesize'));
1192 $last = strtolower($php_upload_size_limit[strlen($php_upload_size_limit)-1]);
1193 switch($last){
1194 case 'g':
1195 $php_upload_size_limit *= 1024;
1196 case 'm':
1197 $php_upload_size_limit *= 1024;
1198 case 'k':
1199 $php_upload_size_limit *= 1024;
1200 }
1201
1202 $MaxSize = min($MaxSize, $php_upload_size_limit);
1203
1204 if($f['error'] != 4 && $f['name']!=''){
1205 if($f['size']>$MaxSize || $f['error']){
1206 echo error_message(str_replace('<MaxSize>', intval($MaxSize / 1024), $Translation['file too large']));
1207 exit;
1208 }
1209 if(!preg_match('/\.('.$FileTypes.')$/i', $f['name'], $ft)){
1210 echo error_message(str_replace('<FileTypes>', str_replace('|', ', ', $FileTypes), $Translation['invalid file type']));
1211 exit;
1212 }
1213
1214 if($NoRename){
1215 $n = str_replace(' ', '_', $f['name']);
1216 }else{
1217 $n = microtime();
1218 $n = str_replace(' ', '_', $n);
1219 $n = str_replace('0.', '', $n);
1220 $n .= $ft[0];
1221 }
1222
1223 if(!file_exists($dir)){
1224 @mkdir($dir, 0777);
1225 }
1226
1227 if(!@move_uploaded_file($f['tmp_name'], $dir . $n)){
1228 echo error_message("Couldn't save the uploaded file. Try chmoding the upload folder '{$dir}' to 777.");
1229 exit;
1230 }else{
1231 @chmod($dir.$n, 0666);
1232 return $n;
1233 }
1234 }
1235 return "";
1236 }
1237
1238 #########################################################
1239
1240 function get_home_links($homeLinks, $default_classes, $tgroup = ''){
1241 if(!is_array($homeLinks) || !count($homeLinks)) return '';
1242
1243 $memberInfo = getMemberInfo();
1244
1245 ob_start();
1246 foreach($homeLinks as $link){
1247 if(!isset($link['url']) || !isset($link['title'])) continue;
1248 if($tgroup != $link['table_group'] && $tgroup != '*') continue;
1249
1250 /* fall-back classes if none defined */
1251 if(!$link['grid_column_classes']) $link['grid_column_classes'] = $default_classes['grid_column'];
1252 if(!$link['panel_classes']) $link['panel_classes'] = $default_classes['panel'];
1253 if(!$link['link_classes']) $link['link_classes'] = $default_classes['link'];
1254
1255 if($memberInfo['admin'] || @in_array($memberInfo['group'], $link['groups']) || @in_array('*', $link['groups'])){
1256 ?>
1257 <div class="col-xs-12 <?php echo $link['grid_column_classes']; ?>">
1258 <div class="panel <?php echo $link['panel_classes']; ?>">
1259 <div class="panel-body">
1260 <a class="btn btn-block btn-lg <?php echo $link['link_classes']; ?>" title="<?php echo preg_replace("/&(#[0-9]+|[a-z]+);/i", "&$1;", html_attr(strip_tags($link['description']))); ?>" href="<?php echo $link['url']; ?>"><?php echo ($link['icon'] ? '<img src="' . $link['icon'] . '">' : ''); ?><strong><?php echo $link['title']; ?></strong></a>
1261 <div class="panel-body-description"><?php echo $link['description']; ?></div>
1262 </div>
1263 </div>
1264 </div>
1265 <?php
1266 }
1267 }
1268
1269 $html = ob_get_contents();
1270 ob_end_clean();
1271
1272 return $html;
1273 }
1274
1275 #########################################################